/**
 * File		: World.java
 * Subject	: Generates and draws the world
 * Author	: Isaac Parenteau (locus2k@gmail.com)
 * Date		: April 16th 2011
 * Note		: Code was borrowed from Google and modified to fit the projects use
 * Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
   You may obtain a copy of the License at

       http://www.apache.org/licenses/LICENSE-2.0

   Unless required by applicable law or agreed to in writing, software
   distributed under the License is distributed on an "AS IS" BASIS,
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   See the License for the specific language governing permissions and
   limitations under the License.
 */
package src.project.cube;

import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.FloatBuffer;
import java.nio.ShortBuffer;
import java.util.ArrayList;

import javax.microedition.khronos.opengles.GL10;

import android.util.Log;

import src.project.util.Matrix;
import src.project.util.Vertex;

public class World {

	public static final String name = World.class.getSimpleName();
	
	private ArrayList<Shape> shapeList = new ArrayList<Shape>();	
	private ArrayList<Vertex> vertexList = new ArrayList<Vertex>();
	
	private int indexCount = 0;
	private int count = 0;

    private FloatBuffer vertexBuffer;
    private FloatBuffer colorBuffer;
    private ShortBuffer indexBuffer;
	
    private boolean loaded = false;
    
    /**
     * Adds a vertex to the vertex list
     * @param x x coordinate of the vertex
     * @param y y coordinate of the vertex
     * @param z z coordinate of the vertex
     * @return the created vertex
     */
	public Vertex addVertex(float x, float y, float z) {
		Vertex vertex = new Vertex(x, y, z, vertexList.size());
		vertexList.add(vertex);
		return vertex;
	}

	/**
	 * Adds a shape to the shape list
	 * @param shape shape to be added
	 */
	public void addShape(Shape shape){
		shapeList.add(shape);
		indexCount += shape.getIndexCount();
	}
	
	/**
	 * Generates the world
	 * Initializes the buffers and sets there values
	 */
	public void generate(){
		Log.v("World", "Generating World");
		ByteBuffer bb = ByteBuffer.allocateDirect(vertexList.size() * 32);
		bb.order(ByteOrder.nativeOrder());
		colorBuffer = bb.asFloatBuffer();
		
		bb = ByteBuffer.allocateDirect(vertexList.size() * 24);
		bb.order(ByteOrder.nativeOrder());
		vertexBuffer = bb.asFloatBuffer();
		
		bb = ByteBuffer.allocateDirect(indexCount * 2);
		bb.order(ByteOrder.nativeOrder());
		indexBuffer = bb.asShortBuffer();
		
		for(Vertex v : vertexList)
			v.put(vertexBuffer, colorBuffer);
		
		for(Shape s : shapeList)
			s.putIndices(indexBuffer);
		
		
		Log.v("World", "Finished Generating World");
	}
	
	/**
	 * Transform the vertex
	 * @param vertex vertex to transform
	 * @param transform transform matrix
	 */
	public void transformVertex(Vertex vertex, Matrix transform) {
		vertex.update(vertexBuffer, transform);
	}
	
	/**
	 * Updates the color buffer to the a new value
	 * @param f the face to update the color
	 * @param value amount to change it by
	 * @return returns the previous value of the color buffer before it was modified
	 */
	public float updateColorBuffer(Face f, float value){
		Vertex v = f.getVertex(3);
		
		float previousColorValue = colorBuffer.get(v.ColorIndex);
		
		colorBuffer.put(v.ColorIndex, value);
		
		return previousColorValue;
	}
	
	/**
	 * Draws the world on screen
	 * @param gl
	 */
	public void draw(GL10 gl){
		colorBuffer.position(0);
		vertexBuffer.position(0);
		indexBuffer.position(0);
		
		gl.glFrontFace(GL10.GL_CW);
		gl.glShadeModel(GL10.GL_FLAT);
		
		if(!loaded){
			gl.glVertexPointer(3, GL10.GL_FLOAT, 0, vertexBuffer);
			gl.glColorPointer(4, GL10.GL_FLOAT, 0, colorBuffer);
		}
		gl.glDrawElements(GL10.GL_TRIANGLES, indexCount, 
				GL10.GL_UNSIGNED_SHORT, indexBuffer);
		
		count++;
	}
}
